package com.mapscloud.bottomnavi.ui.dashboard;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Point;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.util.Log;
import android.util.Size;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;

import com.mapscloud.bottomnavi.databinding.FragmentDashboardBinding;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class DashboardFragment extends Fragment {

    public static final String TAG = "DashboardFragment";
    public static final int START_PREVIEW = 1;

    private DashboardViewModel dashboardViewModel;
    private FragmentDashboardBinding binding;

    private SurfaceHolder surfaceHolder;
    private boolean surfaceCreated = false;
    private boolean cameraOpened = false;
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case START_PREVIEW:
                    if (surfaceCreated && cameraOpened) {
                        startPreview();
                    }
                    break;
            }
        }
    };

    private HandlerThread cameraThread;
    private Handler cameraHandler;

    private CameraManager cameraManager;
    private CameraCharacteristics cameraCharacteristics; // 通过摄像头ID获取
    private CameraDevice cameraDevice; // openCamera之后获取到的相机设备
    private CameraCaptureSession session; // 下request的会话

    public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        dashboardViewModel =
                new ViewModelProvider(this).get(DashboardViewModel.class);

        binding = FragmentDashboardBinding.inflate(inflater, container, false);
        View root = binding.getRoot();

        final TextView textView = binding.textDashboard;
        dashboardViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
            @Override
            public void onChanged(@Nullable String s) {
                textView.setText(s);
            }
        });

        cameraThread = new HandlerThread("CameraThread");
        cameraThread.start();
        cameraHandler = new Handler(cameraThread.getLooper());
        SurfaceHolder surfaceHolder = binding.surfaceCamera.getHolder();
        surfaceHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
                Log.d(TAG, "surfaceCreated");
                surfaceCreated = true;
                DashboardFragment.this.surfaceHolder = surfaceHolder;
                handler.sendEmptyMessage(START_PREVIEW);
            }

            @Override
            public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int i, int i1,
                                       int i2) {
                Log.d(TAG, "surfaceChanged");
            }

            @Override
            public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {
                Log.d(TAG, "surfaceDestroyed");
                surfaceCreated = false;
                DashboardFragment.this.surfaceHolder = null;
            }
        });

        cameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
        try {
            String openCameraId = "1";
            String[] cameraIds = cameraManager.getCameraIdList();
            Log.d(TAG, Arrays.toString(cameraIds));
            boolean hasFrontCamera = false;
            for (int i = 0; i < cameraIds.length; i++) {
                if (cameraIds[i].equals(openCameraId)) {
                    hasFrontCamera = true;
                    break;
                }
            }
            if (hasFrontCamera) {
                cameraCharacteristics = cameraManager.getCameraCharacteristics(openCameraId);

                if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
                    cameraManager.openCamera(openCameraId, new CameraDevice.StateCallback() {
                        @Override
                        public void onOpened(@NonNull CameraDevice camera) {
                            Log.d(TAG, openCameraId + " --- surfaceCreated");
                            cameraOpened = true;
                            cameraDevice = camera;
                            handler.sendEmptyMessage(START_PREVIEW);
                        }

                        @Override
                        public void onDisconnected(@NonNull CameraDevice camera) {
                            Log.d(TAG, openCameraId + " --- onDisconnected");
                        }

                        @Override
                        public void onError(@NonNull CameraDevice camera, int error) {
                            Log.d(TAG, openCameraId + " --- onError");
                        }
                    }, cameraHandler);
                }

            }

        } catch (CameraAccessException e) {
            throw new RuntimeException(e);
        }

        return root;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        if (session != null) {
            try {
                session.stopRepeating();
            } catch (CameraAccessException e) {
                throw new RuntimeException(e);
            }
        }
        if (cameraDevice != null) {
            cameraDevice.close();
            cameraDevice = null;
        }
        binding = null;
    }

    public void startPreview() {
        StreamConfigurationMap configurationMap =
                cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
        Size[] outputSizes = configurationMap.getOutputSizes(SurfaceHolder.class);
        Log.d(TAG, Arrays.toString(outputSizes));

        // 选用最大的尺寸作为预览尺寸
        Display display = binding.surfaceCamera.getDisplay();
        Point outSize = new Point();
        display.getRealSize(outSize);
        int longPixel = Math.max(outSize.x, outSize.y);
        int shortPixel = Math.min(outSize.x, outSize.y);
        boolean hdScreen = longPixel >= 1920 || shortPixel >= 1080;
        Size maxSize;
        if (hdScreen) {
            maxSize = new Size(1920, 1080);
        } else {
            maxSize = new Size(longPixel, shortPixel);
        }
        List<Size> sortOutputSize = Arrays.stream(outputSizes).sorted(new Comparator<Size>() {
            @Override
            public int compare(Size o1, Size o2) {
                int o1Chen = o1.getHeight() * o1.getHeight();
                int o2Chen = o2.getHeight() * o2.getHeight();
                return o2Chen - o1Chen;
            }
        }).collect(Collectors.toList());
        Size bestSize = outputSizes[0];
        for (int i = 0; i < sortOutputSize.size(); i++) {
            if (sortOutputSize.get(i).getWidth() <= maxSize.getWidth()
                    && sortOutputSize.get(i).getHeight() <= maxSize.getHeight()) {
                bestSize = sortOutputSize.get(i);
                break;
            }
        }
        Log.d(TAG, "bestSize = " + bestSize);
        binding.surfaceCamera.setAspectRatio(bestSize.getWidth(), bestSize.getHeight());
        binding.surfaceCamera.post(new Runnable() {
            @Override
            public void run() {
                Surface surface = surfaceHolder.getSurface();

                // 创建 CaptureSession
//                int sessionType = SessionConfiguration.SESSION_REGULAR;
//                List<OutputConfiguration> outputs = new ArrayList<>();
//                OutputConfiguration previewConfig = new OutputConfiguration(surface);
//                outputs.add(previewConfig);
//                Executor executor = new Executor() {
//                    @Override
//                    public void execute(Runnable command) {
//                        handler.post(command);
//                    }
//                };
                CameraCaptureSession.StateCallback cb = new CameraCaptureSession.StateCallback() {
                    @Override
                    public void onConfigured(@NonNull CameraCaptureSession session) {
                        // 创建 CaptureRequest
                        try {
                            DashboardFragment.this.session = session;
                            CaptureRequest.Builder capBuilder =
                                    cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                            capBuilder.addTarget(surface);
                            CaptureRequest capRequest = capBuilder.build();
                            session.setRepeatingRequest(capRequest, null, cameraHandler);
                        } catch (CameraAccessException e) {
                            throw new RuntimeException(e);
                        }
                    }

                    @Override
                    public void onConfigureFailed(@NonNull CameraCaptureSession session) {

                    }
                };
                List<Surface> outputs = new ArrayList<>();
                outputs.add(surface);
                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
//                    SessionConfiguration sessionConfiguration = new SessionConfiguration(sessionType,
//                            outputs, executor, cb);
                    try {
                        cameraDevice.createCaptureSession(outputs, cb, cameraHandler);
                    } catch (CameraAccessException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });

    }


}